package cc.abanlee.module.system.service.oauth2.impl;

import cc.abanlee.framework.common.exception.ServiceException;
import cc.abanlee.framework.common.exception.enums.GlobalErrorCodeConstants;
import cc.abanlee.framework.common.util.date.DateUtils;
import cc.abanlee.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cc.abanlee.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
import cc.abanlee.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO;
import cc.abanlee.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO;
import cc.abanlee.module.system.service.oauth2.OAuth2TokenService;
import cn.hutool.core.util.IdUtil;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.List;

/**
 * @author: create by
 * @version: v1.0
 * @description:
 * @date:2022/9/6
 */
@Service
public class OAuth2TokenServiceImpl implements OAuth2TokenService {


    @Resource
    private OAuth2AccessTokenRedisDAO oauth2AccessTokenRedisDAO;
    @Override
    public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List<String> scopes) {

        OAuth2ClientDO clientDO =new OAuth2ClientDO();
        clientDO.setClientId("123");
        clientDO.setAccessTokenValiditySeconds(3600);
        clientDO.setRefreshTokenValiditySeconds(180000);
        // 创建刷新令牌
        OAuth2RefreshTokenDO refreshTokenDO = createOAuth2RefreshToken(userId, userType, clientDO, scopes);
        // 创建访问令牌
        return createOAuth2AccessToken(refreshTokenDO, clientDO);
    }

    @Override
    public OAuth2AccessTokenDO getAccessToken(String accessToken) {
        // 优先从 Redis 中获取
        OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenRedisDAO.get(accessToken);
        if (accessTokenDO != null) {
            return accessTokenDO;
        }

//        // 获取不到，从 MySQL 中获取
//        accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken);
//        // 如果在 MySQL 存在，则往 Redis 中写入
//        if (accessTokenDO != null && !DateUtils.isExpired(accessTokenDO.getExpiresTime())) {
//            oauth2AccessTokenRedisDAO.set(accessTokenDO);
//        }
        return accessTokenDO;
    }

    @Override
    public OAuth2AccessTokenDO checkAccessToken(String accessToken) {
        OAuth2AccessTokenDO accessTokenDO = getAccessToken(accessToken);
        if (accessTokenDO == null) {
            throw new ServiceException(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌不存在");
        }
        if (DateUtils.isExpired(accessTokenDO.getExpiresTime())) {
            throw new ServiceException(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌已过期");
        }
        return accessTokenDO;
    }

    private OAuth2AccessTokenDO createOAuth2AccessToken(OAuth2RefreshTokenDO refreshTokenDO, OAuth2ClientDO clientDO){
        OAuth2AccessTokenDO accessTokenDO = new OAuth2AccessTokenDO().setAccessToken(generateAccessToken())
                .setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType())
                .setClientId(clientDO.getClientId()).setScopes(refreshTokenDO.getScopes())
                .setRefreshToken(refreshTokenDO.getRefreshToken())
                .setExpiresTime(DateUtils.addDate(Calendar.SECOND, clientDO.getAccessTokenValiditySeconds()));
        // 记录到 Redis 中
        oauth2AccessTokenRedisDAO.set(accessTokenDO);
        return accessTokenDO;
    }


    private OAuth2RefreshTokenDO createOAuth2RefreshToken(Long userId, Integer userType, OAuth2ClientDO clientDO, List<String> scopes) {
        OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setRefreshToken(generateRefreshToken())
                .setUserId(userId).setUserType(userType)
                .setClientId(clientDO.getClientId()).setScopes(scopes)
                .setExpiresTime(DateUtils.addDate(Calendar.SECOND, clientDO.getRefreshTokenValiditySeconds()));
        //oauth2RefreshTokenMapper.insert(refreshToken);

        return refreshToken;
    }

    private static String generateAccessToken() {
        return IdUtil.fastSimpleUUID();
    }

    private static String generateRefreshToken() {
        return IdUtil.fastSimpleUUID();
    }
}
